#include "stdafx.h"
#include "libraries.h"

#include "Application.h"
#include "GUI.h"
#include "DefaultGUIStyle.h"
#include "Texture2DManipulator.h"
#include "StateManager.h"
#include "Filesystem.h"
#include "Engine.h"

using namespace Cvekas;

enum States
{
	STATE1,
	STATE2,
	STATE3,
	STATE_COUNT
};

class State1 : public State
{
public:
	State1(RendererPtr main_renderer, SpriteBatchPtr sprite_batch)
		: State(main_renderer), sprite_batch(sprite_batch)
	{
		Engine e;
		gui = e.getGUI();
	}

	virtual void init()
	{
		background = video_device->getTextureManager()->createTexture2D("state1_background", 32, 32, D3DFMT_X8R8G8B8);
		Texture2DManipulator manipulator(background, false);
		for(int y = 0; y < 32; ++y)
			for(int x = 0; x < 32; ++x)
				manipulator.setPixel(x, y, Color(y%2 ? 128 : 108, 0, 0));
		manipulator.apply();
	}

	virtual void render(const StateManager& state_manager)
	{
		sprite_batch->draw(background, 0, RectF(), RectF(0, 0, 800, 600));
		
		if(gui->doButton(Vector2(10.0f, 10.0f), "Go to state 2"))
			state_manager.switchState(STATE2);
	}

	virtual void fade(const StateManager& state_manager, float amount, uint from, uint to)
	{
		sprite_batch->draw(background, 0, RectF(), RectF(0, 0, 800, 600), Color(255, 255, 255, int(amount * 255.0f)));
	}

private:
	GUIPtr gui;
	SpriteBatchPtr sprite_batch;
	Texture2DPtr background;
};

class State2 : public State
{
public:
	State2(RendererPtr main_renderer, SpriteBatchPtr sprite_batch)
		: State(main_renderer), sprite_batch(sprite_batch)
	{
		Engine e;
		gui = e.getGUI();
	}

	virtual void init()
	{
		background = video_device->getTextureManager()->createTexture2D("state2_background", 32, 32, D3DFMT_X8R8G8B8);
		Texture2DManipulator manipulator(background, false);
		for(int y = 0; y < 32; ++y)
			for(int x = 0; x < 32; ++x)
				manipulator.setPixel(x, y, Color(0, x%2 ? 128 : 118, 0));
		manipulator.apply();
	}

	virtual void render(const StateManager& state_manager)
	{
		sprite_batch->draw(background, 0, RectF(), RectF(0, 0, 800, 600));
		
		if(gui->doButton(Vector2(210.0f, 210.0f), "Go to state 3"))
			state_manager.switchState(STATE3);
	}

	virtual void fade(const StateManager& state_manager, float amount, uint from, uint to)
	{
		sprite_batch->draw(background, 0, RectF(), RectF(0, 0, 800, 600), Color(255, 255, 255, int(amount * 255.0f)));
	}

private:
	GUIPtr gui;
	SpriteBatchPtr sprite_batch;
	Texture2DPtr background;
};

class State3 : public State
{
public:
	State3(RendererPtr main_renderer, SpriteBatchPtr sprite_batch)
		: State(main_renderer), sprite_batch(sprite_batch)
	{
		Engine e;
		gui = e.getGUI();
	}

	virtual void init()
	{
		background = video_device->getTextureManager()->createTexture2D("state3_background", 32, 32, D3DFMT_X8R8G8B8);
		Texture2DManipulator manipulator(background, false);
		for(int y = 0; y < 32; ++y)
			for(int x = 0; x < 32; ++x)
				manipulator.setPixel(x, y, Color(0, 0, (x+y)%2 ? 128 : 108));
		manipulator.apply();
	}

	virtual void render(const StateManager& state_manager)
	{
		sprite_batch->draw(background, 0, RectF(), RectF(0, 0, 800, 600));
		
		if(gui->doButton(Vector2(410.0f, 410.0f), "Go to state 1"))
			state_manager.switchState(STATE1);
	}

	virtual void fade(const StateManager& state_manager, float amount, uint from, uint to)
	{
		sprite_batch->draw(background, 0, RectF(), RectF(0, 0, 800, 600), Color(255, 255, 255, int(amount * 255.0f)));
	}

private:
	GUIPtr gui;
	SpriteBatchPtr sprite_batch;
	Texture2DPtr background;
};


class StatesDemo : public Application
{
public:
	StatesDemo(HINSTANCE instance, const std::string& name, const std::string& log_filename)
		:
	Application(instance, name, log_filename), state_manager(STATE_COUNT, 0.5f)
	{
		Filesystem::init();
	}

	virtual ~StatesDemo() {}

	virtual void initVideoDevice()
	{
		settings->insert("video", VideoSettings());

		(*settings)["video"]["ScreenWidth"] = 800;
		(*settings)["video"]["ScreenHeight"] = 600;
		(*settings)["video"]["VSync"] = false;
		(*settings)["video"]["Fullscreen"] = false;

		window = WindowPtr(new Window(instance, name));
		window->showCursor(false);
		video_device->init(window);
	}

	virtual void init()
	{
		sprite_batch = video_device->createSpriteBatch(main_renderer, 800, 600, 0);
		DefaultGUIStylePtr gui_style(new DefaultGUIStyle(sprite_batch));
		GUIPtr gui(new GUI(gui_style, input));
		setGUI(gui);

		video_device->setClearColor(Color(255, 255, 255));

		input->getMouse()->setVirtualResolution(800, 600);

		StatePtr state1 = StatePtr(new State1(main_renderer, sprite_batch));
		StatePtr state2 = StatePtr(new State2(main_renderer, sprite_batch));
		StatePtr state3 = StatePtr(new State3(main_renderer, sprite_batch));

		state_manager.setState(STATE1, state1);
		state_manager.setState(STATE2, state2);
		state_manager.setState(STATE3, state3);
		state_manager.pushState(STATE1);
	}

	virtual bool update()
	{
		input->getMouse()->update();

		return state_manager.update();
	}

	virtual bool render()
	{
		bool go_on;

		video_device->beginScene();

		go_on = state_manager.render();

		gui->present();
		sprite_batch->present();
		
		main_renderer->render();

		video_device->endScene();

		main_renderer->endFrame();
		return go_on;
	}

private:
	SpriteBatchPtr sprite_batch;
	StateManager state_manager;
};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd)
{
	StatesDemo demo(hInstance, "States Demo", "StatesDemo.log");
	try
	{
		demo.run();
	}
	catch (std::exception& e)
	{
		MessageBox(NULL, e.what(), "Fatal error", NULL);
	}
	return 0;
}
